"""
主窗口UI实现
"""
import os
import sys
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QLabel, QLineEdit, QPushButton, QProgressBar, 
                            QStatusBar, QFileDialog, QTabWidget, QComboBox,
                            QGroupBox, QFormLayout, QSpinBox, QApplication, QTextEdit,
                            QStackedWidget, QCheckBox)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QIcon

class MainWindow(QMainWindow):
    """主窗口类，实现UI界面"""
    
    # 定义信号
    firmware_selected_signal = pyqtSignal(str)
    start_update_signal = pyqtSignal()
    settings_changed_signal = pyqtSignal(dict)
    refresh_device_list_signal = pyqtSignal()  # 新增串口刷新信号
    aboutToClose = pyqtSignal()  # 窗口即将关闭的信号
    
    def __init__(self):
        super().__init__()
        self.init_ui()
        
    def init_ui(self):
        """初始化UI界面"""
        self.resize(700, 400)
        self.setWindowTitle("Fasteur_STM32固件升级软件V1.0.0")
        
        # 创建中央部件和主布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(10)
        
        # 创建TabWidget
        self.tab_widget = QTabWidget()
        main_layout.addWidget(self.tab_widget)
        
        # ========== Tab 1: Firmware Update ==========
        self.firmware_tab = QWidget()
        firmware_layout = QVBoxLayout(self.firmware_tab)
        firmware_layout.setSpacing(4)
        firmware_layout.setContentsMargins(20, 16, 20, 12)
        
        # 标题标签
        title_label = QLabel("固件升级软件")
        title_label.setStyleSheet("font-size: 18px; font-weight: bold;")
        firmware_layout.addWidget(title_label)
        
        # 描述标签
        self.firmware_update_desc_label = QLabel("固件升级使用 XCP on Modbus RTU")
        self.firmware_update_desc_label.setStyleSheet("font-size: 12px; color: #444;")
        firmware_layout.addWidget(self.firmware_update_desc_label)
        
        # 文件选择区域
        firmware_layout.addSpacing(8)
        file_label = QLabel("选择固件文件")
        file_label.setStyleSheet("font-size: 11px;")
        firmware_layout.addWidget(file_label)
        
        file_layout = QHBoxLayout()
        file_layout.setSpacing(4)
        self.file_path_edit = QLineEdit()
        self.file_path_edit.setReadOnly(True)
        file_layout.addWidget(self.file_path_edit)
        
        self.browse_button = QPushButton("选择固件文件")
        self.browse_button.setFixedWidth(90)
        self.browse_button.clicked.connect(self.browse_file)
        file_layout.addWidget(self.browse_button)
        
        firmware_layout.addLayout(file_layout)
        
        # 启动更新按钮
        firmware_layout.addSpacing(6)
        self.update_button = QPushButton("开始升级")
        self.update_button.clicked.connect(self.start_update)
        self.update_button.setEnabled(False)
        self.update_button.setMinimumHeight(28)
        firmware_layout.addWidget(self.update_button)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.progress_bar.setVisible(False)
        self.progress_bar.setMinimumHeight(18)
        firmware_layout.addWidget(self.progress_bar)

        # 信息打印框
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setMinimumHeight(100)
        firmware_layout.addWidget(self.log_text)
        firmware_layout.addStretch()
        
        # 添加Firmware Update Tab
        self.tab_widget.addTab(self.firmware_tab, "固件升级")
        
        # ========== Tab 2: Communication Interface ==========
        self.comm_tab = QWidget()
        comm_layout = QVBoxLayout(self.comm_tab)
        comm_layout.setSpacing(8)
        comm_layout.setContentsMargins(16, 12, 16, 12)

        interface_group = QGroupBox("Interface selection:")
        interface_group.setStyleSheet("QGroupBox { font-size: 12px; }")
        interface_layout = QVBoxLayout(interface_group)
        interface_layout.setContentsMargins(10, 8, 10, 8)
        interface_layout.setSpacing(4)
        self.interface_combo = QComboBox()
        self.interface_combo.setMinimumHeight(28)
        self.interface_combo.addItems([
            "XCP on RS232",
            "XCP on CAN",
            "XCP on USB",
            "XCP on TCP/IP",
            "XCP on Modbus RTU"
        ])
        self.interface_combo.setCurrentIndex(4)  # 默认选中Modbus RTU
        self.interface_combo.currentIndexChanged.connect(self.on_interface_changed)
        interface_layout.addWidget(self.interface_combo)
        comm_layout.addWidget(interface_group)

        # QStackedWidget管理不同通讯设置页
        self.comm_settings_stack = QStackedWidget()

        # 1. RS232设置页
        self.rs232_page = QWidget()
        rs232_layout = QFormLayout(self.rs232_page)
        self.rs232_device_combo = QComboBox()
        self.rs232_device_combo.setEditable(True)  # 设置为可编辑模式，允许用户输入自定义COM口
        self.rs232_device_refresh_button = QPushButton("刷新")
        self.rs232_device_refresh_button.setFixedWidth(50)
        self.rs232_device_refresh_button.clicked.connect(self.on_refresh_device_list)
        rs232_device_layout = QHBoxLayout()
        rs232_device_layout.addWidget(self.rs232_device_combo)
        rs232_device_layout.addWidget(self.rs232_device_refresh_button)
        self.rs232_baudrate_combo = QComboBox()
        self.rs232_baudrate_combo.addItems(["9600", "19200", "38400", "57600", "115200"])
        self.rs232_checksum_combo = QComboBox()
        self.rs232_checksum_combo.addItems(["None", "CRC-8", "CRC-16"])
        rs232_layout.addRow("Device:", rs232_device_layout)
        rs232_layout.addRow("Baudrate:", self.rs232_baudrate_combo)
        rs232_layout.addRow("Checksum:", self.rs232_checksum_combo)
        self.comm_settings_stack.addWidget(self.rs232_page)

        # 2. CAN设置页
        self.can_page = QWidget()
        can_layout = QFormLayout(self.can_page)
        self.can_device_combo = QComboBox()
        self.can_device_combo.setEditable(True)  # 设置为可编辑模式，允许用户输入自定义设备
        self.can_device_combo.addItems(["Peak System PCAN-USB", "Kvaser Leaf Light", "Lawicel CANUSB"])
        self.can_channel_combo = QComboBox()
        self.can_channel_combo.addItems([str(i) for i in range(4)])
        self.can_baudrate_combo = QComboBox()
        self.can_baudrate_combo.addItems(["125 kBit/sec", "250 kBit/sec", "500 kBit/sec", "1 MBit/sec"])
        self.can_transmit_edit = QLineEdit("667")
        self.can_receive_edit = QLineEdit("7E1")
        self.can_extended_checkbox = QCheckBox("29-bit extended CAN identifiers")
        can_layout.addRow("Device:", self.can_device_combo)
        can_layout.addRow("Channel:", self.can_channel_combo)
        can_layout.addRow("Baudrate:", self.can_baudrate_combo)
        can_layout.addRow("Transmit (hex):", self.can_transmit_edit)
        can_layout.addRow("Receive (hex):", self.can_receive_edit)
        can_layout.addRow(self.can_extended_checkbox)
        self.comm_settings_stack.addWidget(self.can_page)

        # 3. USB设置页
        self.usb_page = QWidget()
        usb_layout = QFormLayout(self.usb_page)
        self.usb_vendor_edit = QLineEdit("1D50")
        self.usb_product_edit = QLineEdit("60AC")
        usb_layout.addRow("Vendor ID (hex):", self.usb_vendor_edit)
        usb_layout.addRow("Product ID (hex):", self.usb_product_edit)
        self.comm_settings_stack.addWidget(self.usb_page)

        # 4. TCP/IP设置页
        self.tcpip_page = QWidget()
        tcpip_layout = QFormLayout(self.tcpip_page)
        self.tcpip_addr_edit = QLineEdit("192.168.178.23")
        self.tcpip_port_edit = QLineEdit("1000")
        tcpip_layout.addRow("Address:", self.tcpip_addr_edit)
        tcpip_layout.addRow("Port:", self.tcpip_port_edit)
        self.comm_settings_stack.addWidget(self.tcpip_page)

        # 5. Modbus RTU设置页
        self.modbus_page = QWidget()
        modbus_layout = QFormLayout(self.modbus_page)
        self.modbus_device_combo = QComboBox()
        self.modbus_device_combo.setEditable(True)  # 设置为可编辑模式，允许用户输入自定义COM口
        self.modbus_device_refresh_button = QPushButton("刷新")
        self.modbus_device_refresh_button.setFixedWidth(50)
        self.modbus_device_refresh_button.clicked.connect(self.on_refresh_device_list)
        modbus_device_layout = QHBoxLayout()
        modbus_device_layout.addWidget(self.modbus_device_combo)
        modbus_device_layout.addWidget(self.modbus_device_refresh_button)
        self.modbus_baudrate_combo = QComboBox()
        self.modbus_baudrate_combo.addItems(["9600", "19200", "38400", "57600", "115200"])
        self.modbus_parity_combo = QComboBox()
        self.modbus_parity_combo.addItems(["None", "Even", "Odd"])
        self.modbus_stopbits_combo = QComboBox()
        self.modbus_stopbits_combo.addItems(["1", "2"])
        self.modbus_destination_combo = QComboBox()
        self.modbus_destination_combo.addItems(["1", "2", "3", "4", "5"])
        modbus_layout.addRow("Device:", modbus_device_layout)
        modbus_layout.addRow("Baudrate:", self.modbus_baudrate_combo)
        modbus_layout.addRow("Parity:", self.modbus_parity_combo)
        modbus_layout.addRow("Stopbits:", self.modbus_stopbits_combo)
        modbus_layout.addRow("Destination:", self.modbus_destination_combo)
        self.comm_settings_stack.addWidget(self.modbus_page)

        # 添加到主布局
        comm_layout.addWidget(self.comm_settings_stack)
        self.comm_settings_stack.setCurrentIndex(0)
        self.tab_widget.addTab(self.comm_tab, "Communication Interface")
        
        # ========== Tab 3: Session Protocol ==========
        self.protocol_tab = QWidget()
        protocol_layout = QVBoxLayout(self.protocol_tab)
        protocol_group = QGroupBox("Protocol selection:")
        protocol_group_layout = QVBoxLayout(protocol_group)
        self.protocol_combo = QComboBox()
        self.protocol_combo.addItem("XCP version 1.0")
        protocol_group_layout.addWidget(self.protocol_combo)
        protocol_layout.addWidget(protocol_group)
        connection_group = QGroupBox("Connection")
        connection_layout = QFormLayout(connection_group)
        self.mode_combo = QComboBox()
        self.mode_combo.addItem("0")
        connection_layout.addRow("Mode:", self.mode_combo)
        protocol_layout.addWidget(connection_group)
        security_group = QGroupBox("Security")
        security_layout = QHBoxLayout(security_group)
        self.seed_key_edit = QLineEdit()
        self.seed_key_browse = QPushButton("Browse...")
        security_layout.addWidget(self.seed_key_edit)
        security_layout.addWidget(self.seed_key_browse)
        protocol_layout.addWidget(security_group)
        timeout_group = QGroupBox("Timeouts")
        timeout_layout = QFormLayout(timeout_group)
        self.t1_spinbox = QSpinBox()
        self.t1_spinbox.setRange(0, 10000)
        self.t1_spinbox.setValue(1000)
        timeout_layout.addRow("T1 (ms):", self.t1_spinbox)
        self.t3_spinbox = QSpinBox()
        self.t3_spinbox.setRange(0, 10000)
        self.t3_spinbox.setValue(2000)
        timeout_layout.addRow("T3 (ms):", self.t3_spinbox)
        self.t4_spinbox = QSpinBox()
        self.t4_spinbox.setRange(0, 10000)
        self.t4_spinbox.setValue(10000)
        timeout_layout.addRow("T4 (ms):", self.t4_spinbox)
        self.t5_spinbox = QSpinBox()
        self.t5_spinbox.setRange(0, 10000)
        self.t5_spinbox.setValue(1000)
        timeout_layout.addRow("T5 (ms):", self.t5_spinbox)
        self.t6_spinbox = QSpinBox()
        self.t6_spinbox.setRange(0, 10000)
        self.t6_spinbox.setValue(50)
        timeout_layout.addRow("T6 (ms):", self.t6_spinbox)
        self.t7_spinbox = QSpinBox()
        self.t7_spinbox.setRange(0, 10000)
        self.t7_spinbox.setValue(2000)
        timeout_layout.addRow("T7 (ms):", self.t7_spinbox)
        protocol_layout.addWidget(timeout_group)
        self.tab_widget.addTab(self.protocol_tab, "Session Protocol")
        
        # 连接信号
        self.seed_key_browse.clicked.connect(self.browse_seed_key)
        
        # 连接会话协议设置控件的信号
        self.mode_combo.currentIndexChanged.connect(self.on_protocol_settings_changed)
        self.t1_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        self.t3_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        self.t4_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        self.t5_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        self.t6_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        self.t7_spinbox.valueChanged.connect(self.on_protocol_settings_changed)
        
        # 连接通信接口设置控件的信号
        self.interface_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        # RS232信号
        self.rs232_device_combo.editTextChanged.connect(self.on_comm_settings_changed)
        self.rs232_baudrate_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.rs232_checksum_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        # CAN信号
        self.can_device_combo.editTextChanged.connect(self.on_comm_settings_changed)
        self.can_channel_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.can_baudrate_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.can_transmit_edit.textChanged.connect(self.on_comm_settings_changed)
        self.can_receive_edit.textChanged.connect(self.on_comm_settings_changed)
        self.can_extended_checkbox.stateChanged.connect(self.on_comm_settings_changed)
        # USB信号
        self.usb_vendor_edit.textChanged.connect(self.on_comm_settings_changed)
        self.usb_product_edit.textChanged.connect(self.on_comm_settings_changed)
        # TCP/IP信号
        self.tcpip_addr_edit.textChanged.connect(self.on_comm_settings_changed)
        self.tcpip_port_edit.textChanged.connect(self.on_comm_settings_changed)
        # Modbus RTU信号
        self.modbus_device_combo.editTextChanged.connect(self.on_comm_settings_changed)
        self.modbus_baudrate_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.modbus_parity_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.modbus_stopbits_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        self.modbus_destination_combo.currentIndexChanged.connect(self.on_comm_settings_changed)
        
        # 底部按钮区域
        bottom_layout = QHBoxLayout()
        bottom_layout.addStretch()
        self.exit_button = QPushButton("Exit")
        self.exit_button.clicked.connect(self.close)
        bottom_layout.addWidget(self.exit_button)
        main_layout.addLayout(bottom_layout)
        
        # 状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("Ready")
        
        # 初始化时同步一次界面和描述
        self.on_interface_changed(4)
        
    def browse_file(self):
        """打开文件浏览对话框"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "Select Firmware File", "", "S-Record Files (*.s19);;All Files (*.*)"
        )
        if file_path:
            self.file_path_edit.setText(file_path)
            self.firmware_selected_signal.emit(file_path)
            self.update_button.setEnabled(True)
    
    def update_progress(self, value):
        """更新进度条"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(value)
        QApplication.processEvents()
    
    def show_status_message(self, message):
        """显示状态栏消息"""
        self.status_bar.showMessage(message)
    
    def start_update(self):
        """开始固件更新过程"""
        self.start_update_signal.emit()
        # self.update_button.setEnabled(False)
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
    
    def browse_seed_key(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "Select Seed/Key Algorithm Shared Library File", "", "DLL Files (*.dll);;All Files (*.*)"
        )
        if file_path:
            self.seed_key_edit.setText(file_path)
            # 触发设置更改信号
            self.on_protocol_settings_changed()
    
    def append_log(self, message):
        self.log_text.append(message)
        self.log_text.moveCursor(self.log_text.textCursor().End)
    
    def set_device_list(self, port_list):
        """刷新Device下拉框内容"""
        # 保存当前选择的设备
        current_rs232_device = self.rs232_device_combo.currentText()
        current_modbus_device = self.modbus_device_combo.currentText()
        
        # 清除并重新添加设备列表
        self.rs232_device_combo.clear()
        self.modbus_device_combo.clear()
        
        # 添加系统检测到的端口
        self.rs232_device_combo.addItems(port_list)
        self.modbus_device_combo.addItems(port_list)
        
        # 如果当前选择的设备不在列表中，但有内容（用户手动输入），则添加到列表中
        if current_rs232_device and current_rs232_device not in port_list:
            self.rs232_device_combo.addItem(current_rs232_device)
        
        if current_modbus_device and current_modbus_device not in port_list:
            self.modbus_device_combo.addItem(current_modbus_device)
        
        # 恢复之前的选择
        if current_rs232_device:
            self.rs232_device_combo.setCurrentText(current_rs232_device)
        
        if current_modbus_device:
            self.modbus_device_combo.setCurrentText(current_modbus_device)
    
    def on_refresh_device_list(self):
        """点击刷新按钮时发射信号"""
        self.refresh_device_list_signal.emit()

    def on_interface_changed(self, idx):
        """切换通讯接口时切换设置页并更新固件升级页的描述信息"""
        self.comm_settings_stack.setCurrentIndex(idx)
        selected_interface_text = self.interface_combo.currentText()
        self.firmware_update_desc_label.setText(f"固件升级使用 {selected_interface_text}")

    def get_current_comm_settings(self):
        """根据当前通讯接口收集所有参数，返回settings字典"""
        idx = self.interface_combo.currentIndex()
        interface = self.interface_combo.currentText()
        settings = {'interface': interface}
        if interface == 'XCP on RS232':
            settings['device'] = self.rs232_device_combo.currentText()
            settings['baudrate'] = int(self.rs232_baudrate_combo.currentText())
            settings['checksum'] = self.rs232_checksum_combo.currentIndex()  # 0/1/2
        elif interface == 'XCP on CAN':
            settings['device'] = self.can_device_combo.currentText()
            settings['channel'] = int(self.can_channel_combo.currentText())
            settings['baudrate'] = int(self.can_baudrate_combo.currentText().split()[0]) * 1000
            settings['transmit'] = self.can_transmit_edit.text()
            settings['receive'] = self.can_receive_edit.text()
            settings['extended'] = self.can_extended_checkbox.isChecked()
        elif interface == 'XCP on USB':
            settings['vendor_id'] = self.usb_vendor_edit.text()
            settings['product_id'] = self.usb_product_edit.text()
        elif interface == 'XCP on TCP/IP':
            settings['address'] = self.tcpip_addr_edit.text()
            settings['port'] = self.tcpip_port_edit.text()
        elif interface == 'XCP on Modbus RTU':
            settings['device'] = self.modbus_device_combo.currentText()
            settings['baudrate'] = int(self.modbus_baudrate_combo.currentText())
            settings['parity'] = self.modbus_parity_combo.currentIndex()  # 0/1/2
            settings['stopbits'] = int(self.modbus_stopbits_combo.currentText())
            settings['destination'] = int(self.modbus_destination_combo.currentText())
        return settings

    def get_current_protocol_settings(self):
        """获取当前会话协议设置"""
        settings = {
            'protocol': self.protocol_combo.currentText(),
            'mode': int(self.mode_combo.currentText()),
            'seed_key': self.seed_key_edit.text(),
            'timeouts': {
                't1': self.t1_spinbox.value(),
                't3': self.t3_spinbox.value(),
                't4': self.t4_spinbox.value(),
                't5': self.t5_spinbox.value(),
                't6': self.t6_spinbox.value(),
                't7': self.t7_spinbox.value()
            }
        }
        return settings

    def on_protocol_settings_changed(self):
        """当会话协议设置更改时更新信号"""
        self.settings_changed_signal.emit(self.get_current_protocol_settings())

    def on_comm_settings_changed(self):
        """当通信接口设置更改时更新信号"""
        self.settings_changed_signal.emit(self.get_current_comm_settings())

    def closeEvent(self, event):
        """重写关闭事件，发射aboutToClose信号"""
        self.aboutToClose.emit()
        super().closeEvent(event)
